/*
 * Antonio Canabrava Fraideinberze 7152292
 * Lucas Avelino Sodre Santos      7239086
 * Pedro Rael Garcia               7153021
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <omp.h>
#include "avl.h"

int palindrome(char*);
int isspecial(char);
void palindromeInPhrase(char*);
void palindromeInWord(char*);
int countSpace(char*);
void spaceToken(char*, char*, int, int);
int nextSpace(char*, int, int);
int wordCounter(char*);
void removeSpace(char*);

int main(int argc, char* args[])
{
    char* text;

    if(argc < 2)
    {
        palindromeInWord("shakespe.txt");
        palindromeInPhrase("shakespe.txt");
    }

    else
    {
        palindromeInWord(args[1]);
        palindromeInPhrase(args[1]);
    }

    return 0;
}

int countSpace(char *word)
{
    int i, count;
    int len = strlen(word);

    for(i = 0; i < len; i++)
    {
        word[i] = tolower(word[i]);

        if(word[i] == ' ')
            count++;
    }

    return count;
}

int isspecial(char c)
{
    if(c == ' ' || c == '\t' || c == '\v' || c == '\f' || c == '\r')
        return 1;

    else
        return 0;
}

int nextSpace(char* buffer, int ant, int iterations)
{
    int i, ite = 0;
    int len = strlen(buffer);

    for(i = 0; (i + ant) < len; i++)
    {
        if(buffer[i + ant] == ' ' || buffer[i + ant] == '\t')
        {
            while(buffer[i + ant] == ' ' || buffer[i + ant] == '\t')
                i++;

            ite++;
        }

        if(ite == iterations)
            return i + ant;
    }

    return i + ant;
}

void spaceToken(char* buffer, char* buffer2, int first, int end)
{
    int len, i, j = 0;
    len = end - first;

    for(i = 0; i < len; i++)
        buffer2[i] = buffer[first + i];

    buffer2[len] = '\0';
    return;
}

int wordCounter(char* buffer)
{
    int i, inside = 0, word = 0;
    int len = strlen(buffer);

    for(i = 0; i < len; i++)
    {
        if((!inside) && (buffer[i] - ' '))
        {
            word++;
            inside = 1;
        }

        else if(buffer[i] == ' ')
            inside = 0;
    }

    return word;
}

void removeSpace(char* buffer)
{
    int len, j = 0, i;
    len = strlen(buffer);

    for(i = 0; i < len; i++)
        if(buffer[i] != ' ')
        {
            buffer[j] = buffer[i];
            j++;
        }

    buffer[j] = '\0';
}


int palindrome(char *word)
{
    int i;
    int res = 0;
    int len = strlen(word);

    for(i = 0; i < len; i++)
        if(word[i] == word[len - i - 1])
            continue;

        else
            return 0;

    return 1;
}
void palindromeInPhrase(char* text)
{
    FILE * pFile;
    long lSize;
    char * pch = 0;
    char * buffer;
    char * buffer2;
    size_t result;
    node *phrase = NULL;
    puts("Abrindo o arquivo texto para procurar palavras....");
    pFile = fopen(text, "rb");

    if(pFile == NULL)
    {
        fputs("File error", stderr);
        exit(1);
    }

    // obtain file size:
    fseek(pFile, 0, SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);
    // allocate memory to contain the whole file:
    puts("Alocando memoria para o buffer principal....");
    buffer = (char*) malloc(sizeof(char)*lSize + 1);

    if(buffer == NULL)
    {
        fputs("Memory error", stderr);
        exit(2);
    }

    puts("Alocando memoria para o buffer auxiliar....");
    buffer2 = (char*) malloc(sizeof(char)*lSize + 1);

    if(buffer == NULL)
    {
        fputs("Memory error", stderr);
        exit(2);
    }

    // copy the file into the buffer:
    puts("Copiando arquivo para o buffer principal....");
    result = fread(buffer, 1, lSize, pFile);

    if(result != lSize)
    {
        fputs("Reading error", stderr);
        exit(3);
    }

    /* the whole file is now loaded in the memory buffer. */
    // Close pFile by now
    fclose(pFile);
    int i, j;
    //Size of buffer
    size_t b = lSize;
    //To previne garbage
    buffer[lSize] = '\0';
    //Verify if is puntuation to put spaces the text in phrases
    puts("Trocando pontuacao por espacos....");
    #pragma omp parallel for private(i)

    for(i = 0; i < b; i++)
    {
        if(ispunct(buffer[i]) || isspace(buffer[i]))
            buffer[i] = ' ';
    }

    //Fazer o range de palavras, busca um espaco ate outro espaco
    // da seguinte maneira, uma palavra por vez, depois 2 assim vai
    int prox_space, ant_space, num_space, num_word;
    ant_space = 0;
    num_space = countSpace(buffer);
    num_word = wordCounter(buffer);
    puts("Verificando os palindromos....");
    printf("Palavras no texto %d\n", num_word);
    pFile = fopen("res_phrase_v2.txt", "w");
    #pragma omp parallel for private(i,j,ant_space,prox_space) schedule(guided,20)

    for(j = 1; j <= num_word; j++)
    {
        printf("\r        Verificando %d palavras ao mesmo tempo",j);
        prox_space = 0;
        ant_space = 0;

        for(i = 0; i <= num_word - j ; i++)
        {
            prox_space = nextSpace(buffer, ant_space, j);
            #pragma omp critical
            spaceToken(buffer, buffer2, ant_space, prox_space);
            ant_space = nextSpace(buffer, ant_space, 1);
            //Verify palindromes in phrases
            #pragma omp critical
            {
                removeSpace(buffer2);

                if((find(buffer2, phrase) == NULL) && palindrome(buffer2))
                {
                    phrase = insert(buffer2, phrase);
                    fprintf(pFile, "%s\n", buffer2);
                }
            }
        }
    }

    puts("Limpando a memoria...,\n palindromos encontrados estao no arquivo res_phrase_v2.txt....");
    free(buffer);
    free(buffer2);
    fclose(pFile);
    return;
}

void palindromeInWord(char* text)
{
    FILE * pFile;
    long lSize;
    char * buffer;
    size_t result;
    int i;
    char *pch;
    puts("Abrindo o arquivo texto para procurar palavras....");
    pFile = fopen(text , "rb");

    if(pFile==NULL)
    {
        fputs("File error",stderr);
        exit(1);
    }

    // obtain file size:
    fseek(pFile , 0 , SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);
    puts("Alocando memoria para o buffer principal....");
    // allocate memory to contain the whole file:
    buffer = (char*) malloc(sizeof(char)*lSize+1);

    if(buffer == NULL)
    {
        fputs("Memory error",stderr);
        exit(2);
    }

    // copy the file into the buffer:
    puts("Copiando arquivo para o buffer principal....");
    result = fread(buffer,1,lSize,pFile);

    if(result != lSize)
    {
        fputs("Reading error",stderr);
        exit(3);
    }

    /* the whole file is now loaded in the memory buffer. */
    // terminate
    fclose(pFile);
    //Size of buffer
    size_t b = lSize;
    //To previne garbage
    buffer[lSize] = '\0';
    //   puts(buffer);
    puts("Separando o texto por palavras....");
    #pragma omp parallel for private(i) schedule(guided,20)

    for(i=0; i < b ; i++)
    {
        buffer[i] = tolower(buffer[i]);

        if(ispunct(buffer[i]) || isspace(buffer[i]))
            buffer[i]='\n';
    }

    node *words = NULL;
    pFile = fopen("res_word_v2.txt" , "w");
    pch = strtok(buffer,"\n");
    puts("Verificando os palindromos....");

    while(pch != NULL)
    {
        if(find(pch,words)== NULL && palindrome(pch))
        {
            words = insert(pch,words);
            fprintf(pFile,"%s\n",pch);
        }

        pch = strtok(NULL,"\n");
    }

    puts("Limpando a memoria...,\n palindromos encontrados estao no arquivo res_word_v2.txt....");
    free(buffer);
    fclose(pFile);
    return;
}
